package config

import (
	"fmt"
	"os"
	"sync"
	"time"

	"github.com/spf13/viper"
)

var Prefix string
var Email *EmailConfig

// Config 使用结构体来映射 .ini 文件中的各个 section
type Config struct {
	App         *AppConfig
	MySQL       *MySQLConfig
	Redis       *RedisConfig
	Oss         *OssConfig
	ShortLinks  *LinksConfig
	EmailConfig *EmailConfig
}

// AppConfig 使用结构体来映射 app 部分 .ini 文件中的各个 section
type AppConfig struct {
	DPass      string `ini:"dpass"`
	Env        string `ini:"env"`
	Port       string `ini:"port"`
	LogFile    string `ini:"logFile"`
	LogConsole bool   `ini:"logConsole"`
	LogLevel   string `ini:"logLevel"`
}

// MySQLConfig 使用结构体来映射 mysql 部分
type MySQLConfig struct {
	Host        string `ini:"host"`
	Port        int    `ini:"port"`
	User        string `ini:"user"`
	Password    string `ini:"password"`
	DBName      string `ini:"dbname"`
	MaxIdleConn int    `ini:"maxIdleConn"`
	MaxOpenConn int    `ini:"maxOpenConn"`
}

// RedisConfig 使用结构体来映射 redis 部分
type RedisConfig struct {
	Addr         string        `ini:"addr"`
	Pass         string        `ini:"pass"`
	DB           int           `ini:"db"`
	PoolSize     int           `ini:"poolSize"`
	MinIdleConns int           `ini:"minIdleConns"`
	DialTimeout  time.Duration `ini:"dialTimeout"`
	ReadTimeout  time.Duration `ini:"readTimeout"`
	WriteTimeout time.Duration `ini:"writeTimeout"`
}

// OssConfig 使用结构体来映射 oss 部分
type OssConfig struct {
	Endpoint        string `ini:"endpoint"`
	AccessKeyID     string `ini:"accessKeyId"`
	AccessKeySecret string `ini:"accessKeySecret"`
	BucketName      string `ini:"bucketName"`
}

// LinksConfig 使用结构体来映射 redis 部分
type LinksConfig struct {
	Prefix string `ini:"prefix"`
}

// EmailConfig 使用结构体来映射 email 部分
type EmailConfig struct {
	SmtpHost string `ini:"smtpHost"`
	SmtpPort string `ini:"smtpPort"`
	Sender   string `ini:"sender"`   //你的QQ邮箱
	Password string `ini:"password"` //QQ邮箱的SMTP授权码
}

var once sync.Once

// 使用 Viper
// Viper 是一个功能强大的配置管理库，支持多种配置文件格式（包括 .ini），
// 并且提供了自动映射配置到结构体的功能。
// Viper 还支持配置文件的热重载，这意味着您可以在不重启应用程序的情况下更新配置。

// Init 加载配置文件并返回 Config 结构体实例
func InitConfig(file string) (*Config, error) {
	var err error
	cfg := &Config{}

	once.Do(func() {
		viper.SetConfigFile(file) // 设置配置文件
		//viper.SetConfigName("app") // 配置文件名称 (没有扩展名)
		//viper.SetConfigType("ini") // 配置文件类型
		//viper.AddConfigPath(".")   // 配置文件所在路径
		viper.AutomaticEnv() // 从环境变量中读取敏感信息

		if err = viper.ReadInConfig(); err != nil {
			err = fmt.Errorf("error reading config file, %s", err)
			return
		}

		if err = viper.Sub("app").Unmarshal(&cfg.App); err != nil {
			err = fmt.Errorf("unable to decode 'app' section into struct, %v", err)
			return
		}
		if err = viper.Sub("mysql").Unmarshal(&cfg.MySQL); err != nil {
			err = fmt.Errorf("unable to decode 'mysql' section into struct, %v", err)
			return
		}
		if err = viper.Sub("redis").Unmarshal(&cfg.Redis); err != nil {
			err = fmt.Errorf("unable to decode 'redis' section into struct, %v", err)
			return
		}
		if err = viper.Sub("oss").Unmarshal(&cfg.Oss); err != nil {
			err = fmt.Errorf("unable to decode 'oss' section into struct, %v", err)
			return
		}
		if err = viper.Sub("shortLink").Unmarshal(&cfg.ShortLinks); err != nil {
			err = fmt.Errorf("unable to decode 'shortLink' section into struct, %v", err)
			return
		}
		Prefix = cfg.ShortLinks.Prefix
		if err = viper.Sub("email").Unmarshal(&cfg.EmailConfig); err != nil {
			err = fmt.Errorf("unable to decode 'email' section into struct, %v", err)
			return
		}
		Email = cfg.EmailConfig
		//确保环境变量中的敏感信息被正确读取
		if dbPassword := os.Getenv("1234"); dbPassword != "" {
			cfg.App.DPass = dbPassword
		}
	})

	if err != nil {
		return nil, err
	}
	return cfg, nil
}
